#include "Format.h"

#include <map>
#include <limits>
#include <boost/regex.hpp>

#include "Utils.h"
#include "Lang.h"

void FormatValidator::StructMembers::recurse(YAML::Node definition, std::string structname) {
    SYVDEBUGOUT(SYVTRACE,
    printf("StructMembers::recurse(def, \"%s\"). Def:\n", structname.c_str());
    dump(definition);
    )

    if(definition[SYV_KEYWORD_TYPE]) {
        std::string type = val->getBaseType(definition[SYV_KEYWORD_TYPE].Scalar());
        YAML::Node t = val->getType(type);
        if(!t) {
            throw ValidityException(syvTypeNotFound, "%s \"%s\" not found.\n", SYV_KEYWORD_TYPE, type.c_str());
            error = 1;
            return;
        }
        if(!structname.length())
            recurse(t, type);
        else
            recurse(t, structname);
        return;
    }

    YAML::Node strct = definition[SYV_KEYWORD_STRUCT];
    if(YAML::Node inherits = strct[SYV_KEYWORD_INHERITS]) {
        if(!inherits.IsSequence()) { throw ValidityException(syvSequenceExpected, "\"%s\" not sequence.\n", SYV_KEYWORD_INHERITS); dump(inherits); error = 2; return; } // TODO
        for(YAML::Node::const_iterator i = inherits.begin(); i != inherits.end() && !error; i++) {
            YAML::Node t = val->getType(i->Scalar());
            if(!t) {
                throw ValidityException(syvTypeNotFound, "%s \"%s\" not found.\n", SYV_KEYWORD_TYPE, i->Scalar().c_str());
                error = 3;
                return;
            } else {
                if(!structname.length())
                    recurse(t, i->Scalar());
                else
                    recurse(t, structname);
            }
        }
    }

    if(error) return;

    for(YAML::Node::const_iterator i = strct.begin(); i != strct.end(); i++) {
        std::string k = i->first.Scalar();
        if(!k.compare(SYV_KEYWORD_INHERITS)) continue;
        if(!members[k]) {
            if(!structname.length())
                members[k] = copy(i->second);
            else {
                YAML::Node ref(YAML::NodeType::Map);
                ref[SYV_KEYWORD_TYPE] = structname + SYV_STRUCT_MEMBER_SEPARATOR + i->first.Scalar();
                members[k] = ref;
            }
        } else {
            throw ValidityException(syvDuplicateMember, "Duplicate member \"%s\".\n", k.c_str());
            error = 4;
            return;
        }
    }
}

YAML::Node FormatValidator::StructMembers::getStructMembers(FormatValidator*fv, YAML::Node structdefinition) {
    SYVDEBUGOUT(SYVTRACE,
    printf("getStructMembers(fv, structdefinition); structdefinition:\n");
    dump(structdefinition);
    )

    if(!fv) return YAML::Node(YAML::NodeType::Undefined);

    StructMembers sm(fv);

    sm.recurse(structdefinition);

    if(sm.error) return YAML::Node(YAML::NodeType::Undefined);
    else {
        return YAML::Node(sm.members);
    }
}

bool FormatValidator::StructMembers::isValid(FormatValidator*fv, YAML::Node structdefinition) {
    StructMembers sm(fv);
    return sm.validate(structdefinition);
}

bool FormatValidator::StructMembers::validate(YAML::Node definition) {
    SYVDEBUGOUT(SYVTRACE,
    printf("StructMembers::validate(def). Def:\n");
    dump(definition);
    )

    if(definition[SYV_KEYWORD_TYPE]) {
        std::string type = val->getBaseType(definition[SYV_KEYWORD_TYPE].Scalar());
        YAML::Node t = val->getType(type);
        if(!t) {
            throw DDLException(syvTypeNotFound, "%s \"%s\" not found.\n", SYV_KEYWORD_TYPE, type.c_str());
            error = 1;
            return false;
        }
        return validate(t);
    }

    YAML::Node strct = definition[SYV_KEYWORD_STRUCT];
    if(YAML::Node inherits = strct[SYV_KEYWORD_INHERITS]) {
        if(!inherits.IsSequence()) { throw DDLException(syvSequenceExpected, "\"%s\" not sequence.\n", SYV_KEYWORD_INHERITS); dump(inherits); error = 2; return false; } // TODO
        for(YAML::Node::const_iterator i = inherits.begin(); i != inherits.end() && !error; i++) {
            YAML::Node t = val->getType(i->Scalar());
            if(!t) {
                throw DDLException(syvTypeNotFound, "%s \"%s\" not found.\n", SYV_KEYWORD_TYPE, i->Scalar().c_str());
                error = 3;
                return false;
            } else {
                if(!validate(t)) return false;
            }
        }
    }

    if(error) return false;

    for(YAML::Node::const_iterator i = strct.begin(); i != strct.end(); i++) {
        std::string k = i->first.Scalar();
        if(!k.compare(SYV_KEYWORD_INHERITS)) continue;
        if(!members[k]) {
            members[k] = 1;//copy(i->second);
        } else {
            throw DDLException(syvDuplicateMember, "Duplicate member \"%s\".\n", k.c_str());
            error = 4;
            return false;
        }
    }
    
    return true;
}

// FormatValidator::EnumValues

YAML::Node FormatValidator::EnumValues::getEnumValues(FormatValidator*fv, YAML::Node enumdefinition) {
    if(!fv) return YAML::Node(YAML::NodeType::Undefined);
    EnumValues ev(fv);
    ev.recurse(enumdefinition);
    if(ev.error) return YAML::Node(YAML::NodeType::Undefined);
    else return ev.values;
}

void FormatValidator::EnumValues::recurse(YAML::Node enumdefinition) { // TODO: split this function up in two: one validateEnumValues/validateEnumType and one getEnumValues, which assumes valid.
    YAML::Node enm = enumdefinition[SYV_KEYWORD_ENUM];
    if(YAML::Node inherits = enm[SYV_KEYWORD_INHERITS]) {
//        if(!inherits.IsSequence()) { printf("\"%s\" not sequence.\n", SYV_KEYWORD_INHERITS); error = 1; return; } // TODO
        for(YAML::Node::const_iterator i = inherits.begin(); i != inherits.end() && !error; i++) {
            YAML::Node t = val->getType(i->Scalar());
            if(!t) {
//                printf("Type \"%s\" not found.\n", i->Scalar().c_str());
                error = 2;
                return;
            } else {
                recurse(t);
            }
        }
    }

    if(error) return;

    YAML::Node n = enm[SYV_KEYWORD_VALUES];

    if(n.IsSequence()) {
        if(!mapOrSequence) mapOrSequence = 1;
        else if(mapOrSequence != 1) {
//            printf("Incompatible enums.\n");
            error = 3; // TODO
            return;
        }
        for(YAML::Node::const_iterator v = n.begin(); v != n.end(); v++) {
            if(sequenceHasValue(values, v->Scalar())) {
//                printf("Duplicate value: \"%s\".\n", v->Scalar().c_str());
                error = 4; // TODO
                return;
            }
            values.push_back(*v);
        }
    } else if(n.IsMap()) {
        if(!mapOrSequence) mapOrSequence = 2;
        else if(mapOrSequence != 2) {
//            printf("Incompatible enums.\n"); // TODO
            error = 3;
            return;
        }
        for(YAML::Node::const_iterator v = n.begin(); v != n.end(); v++) {
            if(mapHasKeyWithValue(values, v->second.Scalar())) {
//                printf("Duplicate value: \"%s\".\n", v->second.Scalar().c_str()); // TODO
                error = 5;
                return;
            }
            values[v->first.Scalar()] = v->second;
        }
    } else if(!n.IsDefined()) {
        if(!enm[SYV_KEYWORD_INHERITS]) {
//            printf("Neither inherits nor values.\n"); // TODO
            error = 6;
        }
    } else {
//        printf("Internal error.\n"); 
        error = 7;
        return; // TODO        
    }
    return;
}

bool FormatValidator::EnumValues::validate(YAML::Node enumdefinition) {
    YAML::Node enm = enumdefinition[SYV_KEYWORD_ENUM];
    if(YAML::Node inherits = enm[SYV_KEYWORD_INHERITS]) {
        if(!inherits.IsSequence()) { throw DDLException(syvSequenceExpected, "\"%s\" not sequence.\n", SYV_KEYWORD_INHERITS); error = 1; return false; } // TODO
        for(YAML::Node::const_iterator i = inherits.begin(); i != inherits.end() && !error; i++) {
            YAML::Node t = val->getType(i->Scalar());
            if(!t) {
                throw DDLException(syvTypeNotFound, "%s \"%s\" not found.\n", SYV_KEYWORD_TYPE, i->Scalar().c_str());
                error = 2;
                return false;
            } else {
                if(!validate(t)) return false;
            }
        }
    }

    if(error) return false;

    YAML::Node n = enm[SYV_KEYWORD_VALUES];

    if(n.IsSequence()) {
        if(!mapOrSequence) mapOrSequence = 1;
        else if(mapOrSequence != 1) {
            throw DDLException(syvIncompatibleEnums, "Incompatible enums.\n");
            error = 3; // TODO
            return false;
        }
        for(YAML::Node::const_iterator v = n.begin(); v != n.end(); v++) {
            if(sequenceHasValue(values, v->Scalar())) {
                throw DDLException(syvDuplicateValue, "Duplicate value: \"%s\".\n", v->Scalar().c_str());
                error = 4; // TODO
                return false;
            }
            values.push_back(*v);
        }
    } else if(n.IsMap()) {
        if(!mapOrSequence) mapOrSequence = 2;
        else if(mapOrSequence != 2) {
            throw DDLException(syvIncompatibleEnums, "Incompatible enums.\n"); // TODO
            error = 3;
            return false;
        }
        for(YAML::Node::const_iterator v = n.begin(); v != n.end(); v++) {
            if(mapHasKeyWithValue(values, v->second.Scalar())) {
                throw DDLException(syvDuplicateValue, "Duplicate value: \"%s\".\n", v->second.Scalar().c_str()); // TODO
                error = 5;
                return false;
            }
            values[v->first.Scalar()] = v->second;
        }
    } else if(!n.IsDefined()) {
        if(!enm[SYV_KEYWORD_INHERITS]) {
            throw DDLException(syvEmptyEnum, "Neither inherits nor values.\n"); // TODO
            error = 6;
            return false;
        }
    } else {
        throw DDLException(syvInvalidNodeType, "Invalid node type(%u).\n", n.Type()); 
        error = 7;
        return false;      
    }
    return true;
}

// FormatValidator

FormatValidator::FormatValidator(YAML::Node format, unsigned int flags) {
    this->flags = flags;
    if(flags & syvCopyInput) this->format = copy(format);
    else this->format = format;
    valid = validateFormat();
}

bool FormatValidator::isEnumType(std::string t) {
    YAML::Node n = getType(t);
    if(!n) return false;
    if(n[SYV_KEYWORD_ENUM]) return true;
    if(n[SYV_KEYWORD_STRUCT]) return false;
    if(!n[SYV_KEYWORD_TYPE]) return false;
    return isEnumType(n[SYV_KEYWORD_TYPE].Scalar());
}

bool FormatValidator::isFloatingPointType(std::string t) {
    if(!t.compare(SYV_TYPE_FLOAT)) return true;
    else if(!t.compare(SYV_TYPE_DOUBLE)) return true;
    else return false;
}

bool FormatValidator::isNumericType(std::string type) {
    if(!type.compare(SYV_TYPE_UINT)) return true;
    else if(!type.compare(SYV_TYPE_INT)) return true;
    else if(!type.compare(SYV_TYPE_UINT64)) return true;
    else if(!type.compare(SYV_TYPE_INT64)) return true;
    else if(!type.compare(SYV_TYPE_FLOAT)) return true;
    else if(!type.compare(SYV_TYPE_DOUBLE)) return true;
    else {
        YAML::Node t;
        t = getType(type);
        if(!t) return false;
        if(t[SYV_KEYWORD_ENUM] || t[SYV_KEYWORD_STRUCT] || !t[SYV_KEYWORD_TYPE]) {
            return false;
        }
        std::string tp = t[SYV_KEYWORD_TYPE].Scalar();
        return isNumericType(tp);
    }
}

bool FormatValidator::isIntegerType(std::string t) {
    return isNumericType(t) && !isFloatingPointType(t);
}

bool FormatValidator::isBuiltinType(std::string t) {
    if(!t.compare(SYV_TYPE_UINT)) return true;
    else if(!t.compare(SYV_TYPE_INT)) return true;
    else if(!t.compare(SYV_TYPE_UINT64)) return true;
    else if(!t.compare(SYV_TYPE_INT64)) return true;
    else if(!t.compare(SYV_TYPE_FLOAT)) return true;
    else if(!t.compare(SYV_TYPE_DOUBLE)) return true;
    else if(!t.compare(SYV_TYPE_BOOL)) return true;
    else if(!t.compare(SYV_TYPE_STRING)) return true;
    else if(!t.compare(SYV_TYPE_CHAR)) return true;
    else return false;
}

bool FormatValidator::isArrayType(std::string t) {
    if(!t.length()) return false;
    SYVDEBUGOUT(SYVTRACE, printf("isArrayType(%s)\n", t.c_str());)
    if(t.find(SYV_TYPE_ARRAY_OPEN) == std::string::npos) {
        YAML::Node type = getType(t);
        if(type) {
            return isArrayType(type[SYV_KEYWORD_TYPE].Scalar());
        }
        return false;
    }
    std::string::size_type p = t.find_last_of(SYV_TYPE_ARRAY_CLOSE);
    if(p == std::string::npos) return false; // TODO: exception internal error EDIT: nope, see above when recursing can be empty
    unsigned sz = strlen(SYV_TYPE_ARRAY_OPEN);
    std::string type = t.substr(sz, p-sz);
    SYVDEBUGOUT(SYVTRACE, printf("Calling isType(%s)\n", type.c_str());)
    return isType(type);
}

std::string FormatValidator::arrayElementType(std::string t) { // XXX: only call when isArrayType() was true.
    SYVDEBUGOUT(SYVTRACE, printf("arrayElementType('%s')\n", t.c_str());)
    if(t.find(SYV_TYPE_ARRAY_OPEN) != 0) {
        std::string s = t;
        do {
            YAML::Node n = getType(s);
            if(!n || n[SYV_KEYWORD_STRUCT] || n[SYV_KEYWORD_ENUM]) return t;
            s = n[SYV_KEYWORD_TYPE].Scalar();
        } while(s.length() && (s.find(SYV_TYPE_ARRAY_OPEN) != 0));
        t = s;
    }
    std::string::size_type p = t.find_last_of(SYV_TYPE_ARRAY_CLOSE);
    if(p == std::string::npos) return t;
    unsigned sz = strlen(SYV_TYPE_ARRAY_OPEN);
    std::string type = t.substr(sz, p-sz);
    return type;
}

bool FormatValidator::isType(std::string t) {
    SYVDEBUGOUT(SYVTRACE, printf("isType(%s)\n", t.c_str());)

    if(types[t]) { return true; }

    if(isBuiltinType(t)) return true;
    if(isArrayType(t)) return true;

    YAML::Node def = getType(t);
    return def;
}

bool FormatValidator::hasBooleanValue(YAML::Node n) {
    if(!n.IsScalar()) return false;
    try {
        n.as<bool>();
    } catch(const YAML::TypedBadConversion<bool> e) {
        return false;
    }
    return true;
}

bool FormatValidator::validateTypeDefinitionEnum(std::string name, YAML::Node n) {
    if(!n.Type() == YAML::NodeType::Map) { throw DDLException(syvMapExpected, "%s not map", SYV_KEYWORD_ENUM); return false; }
    YAML::Node m = n[SYV_KEYWORD_ENUM];
    if(!m) return false;

    if(m.size() > 4) { throw DDLException(syvTooManyKeywords, "There can be no more than %u different keywords in an enum type definition.\n", 4); return false; }
    YAML::Node values(m[SYV_KEYWORD_VALUES]);
//    if(!values) return false;
    if(values.Type() != YAML::NodeType::Map && values.Type() != YAML::NodeType::Sequence) {
        if(values.Type() != YAML::NodeType::Undefined) {
            throw DDLException(syvInvalidNodeType, "Wrong node type for %s in %s.\n", SYV_KEYWORD_VALUES, SYV_KEYWORD_ENUM);
            return false;
        }
    }
    YAML::Node allowNull(m[SYV_KEYWORD_ALLOWNULL]);
    if(allowNull && !hasBooleanValue(allowNull)) { throw DDLException(syvValueNotBoolean, "%s not boolean", SYV_KEYWORD_ALLOWNULL); return false; }
    if(!EnumValues::isValid(this, n)) return false; // TODO: move more of this function to that function.
    YAML::Node dflt(m[SYV_KEYWORD_DEFAULT]);
    if(dflt) {
        if(!isValidValueForEnum(n, dflt)) {
            throw DDLException(syvInvalidValue, "Invalid %s value for %s", SYV_KEYWORD_DEFAULT, SYV_KEYWORD_ENUM);
            return false;
        }
//        if(!satisfiesTypeRequirements("", dflt, n)) return false; //TODO
    }
    return true;
}

bool FormatValidator::isValidNumberForType(std::string type, std::string value) {
    char *s = new char[1024]; // TODO: is there not a better way than this?
    strcpy(s, value.c_str());
    char* endptr;             // needed because endptr must be char*
    bool r = true;
    try {
        if(!type.compare(SYV_TYPE_FLOAT)) {
                float f = strtof(s, &endptr);
        } else if(!type.compare(SYV_TYPE_DOUBLE)) {
                double d = strtod(s, &endptr);
        } else if(!type.compare(SYV_TYPE_INT)) {
                long l = strtol(s, &endptr, 10);
                if(l > std::numeric_limits<int>::max()) r = false;
                if(l < std::numeric_limits<int>::min()) r = false;
        } else if(!type.compare(SYV_TYPE_INT64)) {
                long l = strtol(s, &endptr, 10);
        } else if(!type.compare(SYV_TYPE_UINT64)) {
                long l = strtol(s, &endptr, 10);
        } else if(!type.compare(SYV_TYPE_UINT)) {
                long l = strtol(s, &endptr, 10);
                if((unsigned long)l > 0xFFFFFFFF) r = false;
        } else {
            // Not a numeric scalar type.
            r = false;
        }
    } catch(const std::invalid_argument e) {
        r = false;
    } catch(const std::out_of_range e) {
        r = false;
    }
    if(r && ((endptr-s) < strlen(s))) 
        r = false;
    delete s;
    return r;
}

bool FormatValidator::isString(std::string type) {
    SYVDEBUGOUT(SYVTRACE, printf("isString(%s)\n", type.c_str());)
    if(!type.compare(SYV_TYPE_STRING)) return true;
    if(isBuiltinType(type)) return false;
    if(isArrayType(type)) return false;
    YAML::Node t = getType(type);
    if(!t) {
        SYVDEBUGOUT(SYVTRACE, printf("isString: type %s not found.\n", type.c_str());)
        return false;
    }
    return isString(t[SYV_KEYWORD_TYPE].Scalar());
}

YAML::Node FormatValidator::getType(std::string type) {
// Type of "Vector::w" returns var definition of member w in struct type Vector.
// Type of "Vertex::position::x" returns var definition of member x in struct member position in type Vertex.
// Etc.

    SYVDEBUGOUT(SYVTRACE, printf("getType('%s')\n", type.c_str());)

    if(isBuiltinType(type)) {
        return YAML::Node(YAML::NodeType::Undefined);
    }
    std::string::size_type p = 0;
    if((p = type.find(SYV_STRUCT_MEMBER_SEPARATOR)) != std::string::npos) {
        std::string structname = type.substr(0, p);
        unsigned sz = strlen(SYV_STRUCT_MEMBER_SEPARATOR);
        std::string membername = type.substr(p + sz, type.length() - p - sz);
        
        YAML::Node baseType;
        do { 
            YAML::Node n = format[SYV_KEYWORD_TYPEDEFINITIONS][structname];
            if(!n[SYV_KEYWORD_STRUCT]) {
                if(n[SYV_KEYWORD_TYPE])
                    structname = n[SYV_KEYWORD_TYPE].Scalar();
                else
                    return YAML::Node(YAML::NodeType::Undefined);
            }
        } while(!format[SYV_KEYWORD_TYPEDEFINITIONS][structname]);//getType(getBaseType(structname));
        if(types[structname] && !types[structname].IsNull()) 
            baseType = types[structname];
        else
            baseType = format[SYV_KEYWORD_TYPEDEFINITIONS][structname];
        if(!baseType) {
            if(!validateTypeDefinition(structname, format[SYV_KEYWORD_TYPEDEFINITIONS][structname])) return YAML::Node(YAML::NodeType::Undefined);
            baseType = types[structname];
        }
        if(!baseType[SYV_KEYWORD_STRUCT][membername]) {
            if((p = membername.find(SYV_STRUCT_MEMBER_SEPARATOR)) != std::string::npos) {
                std::string structmember = membername.substr(0, p);
                std::string structmembertype = baseType[SYV_KEYWORD_STRUCT][structmember][SYV_KEYWORD_TYPE].Scalar();
                YAML::Node structmemberdef = getType(structmembertype);
                if(!structmemberdef) return YAML::Node(YAML::NodeType::Undefined);
                std::string x = membername.replace(0, p, structmembertype);
                return getType(x);
            } else {
                return YAML::Node(YAML::NodeType::Undefined);
            }
        }
        return baseType[SYV_KEYWORD_STRUCT][membername];
    }
    if(!type.length()) return YAML::Node(YAML::NodeType::Undefined);
    if(!types[type]) {
        if(!types[type].IsNull()) {
            if(type.find(SYV_TYPE_ARRAY_OPEN) == std::string::npos) {
                if(!validateTypeDefinition(type, format[SYV_KEYWORD_TYPEDEFINITIONS][type])) { 
                    types[type] = YAML::Node(YAML::NodeType::Null);
                    return YAML::Node(YAML::NodeType::Undefined);
                }
            } else return YAML::Node(YAML::NodeType::Undefined);
        } else return YAML::Node(YAML::NodeType::Undefined);
    }
    return types[type];
}

bool FormatValidator::isValidValueForEnum(YAML::Node enumdefinition, YAML::Node value) {
//    if(!enumdefinition || !enumdefinition[SYV_KEYWORD_ENUM]) return false;
    if(!value.IsScalar()) return false;
    if(value.IsNull()) {
//        if(!(enumdefinition[SYV_KEYWORD_ENUM][SYV_KEYWORD_ALLOWNULL] && enumdefinition[SYV_KEYWORD_ENUM][SYV_KEYWORD_ALLOWNULL].as<bool>())) return false; //TODO: not here
    } else {
        YAML::Node v = EnumValues::getEnumValues(this, enumdefinition);
        if(!v || v.size() == 0) { 
            if(!valid)
                throw DDLException(syvEmptyEnum, "There are no %s in this %s.\n", SYV_KEYWORD_VALUES, SYV_KEYWORD_ENUM); 
            else
                throw ValidityException(syvEmptyEnum, "There are no %s in this %s.\n", SYV_KEYWORD_VALUES, SYV_KEYWORD_ENUM); // TODO
            return false; 
        }
        if(v.IsMap()) {
            for(YAML::Node::const_iterator i = v.begin(); i != v.end(); i++) {
                if(!i->first.Scalar().compare(value.Scalar())) return true;
            }
            return false;
        } else if(v.IsSequence()) {
            if(sequenceHasValue(v, value.Scalar())) return true;
            return false;
        } else {
            if(!valid)
                throw DDLException(syvValueNotFoundInEnum, "Value \"%s\" not defined in %s\n", value.Scalar().c_str(), SYV_KEYWORD_ENUM);
            else
                throw ValidityException(syvValueNotFoundInEnum, "Value \"%s\" not defined in %s\n", value.Scalar().c_str(), SYV_KEYWORD_ENUM); // TODO
            return false;
        }
    }

    return false;
}

double FormatValidator::getEffectiveMin(YAML::Node def) {

    double min;

    if(def[SYV_KEYWORD_MIN]) {
        min = def[SYV_KEYWORD_MIN].as<double>();
        return min;
    } else {
        min = -std::numeric_limits<double>::infinity();
    }
    
    std::string type = def[SYV_KEYWORD_TYPE].Scalar();
    do {
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            if(t[SYV_KEYWORD_MIN]) {
                double u = t[SYV_KEYWORD_MIN].as<double>();
                return u;
            }
        } else break;
        type = t[SYV_KEYWORD_TYPE].Scalar();
    } while(1!=2);

    return min;
}

double FormatValidator::getEffectiveMax(YAML::Node def) {

    double max;

    if(def[SYV_KEYWORD_MAX]) {
        max = def[SYV_KEYWORD_MAX].as<double>();
        return max;
    } else {
        max = std::numeric_limits<double>::infinity();
    }
    
    std::string type = def[SYV_KEYWORD_TYPE].Scalar();
    do {
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            if(t[SYV_KEYWORD_MAX]) {
                double u = t[SYV_KEYWORD_MAX].as<double>();
                return u;
            }
        } else {
            break;
        }
        type = t[SYV_KEYWORD_TYPE].Scalar();
    } while(1!=2);

    return max;
}

unsigned FormatValidator::getEffectiveMaxlen(YAML::Node def) {

    unsigned maxlen;

    if(def[SYV_KEYWORD_MAXLEN]) {
        maxlen = def[SYV_KEYWORD_MAXLEN].as<unsigned>();
        return maxlen;
    }

    std::string type = def[SYV_KEYWORD_TYPE].Scalar();

    do {
//        bool a = isArrayType(type);
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            if(t[SYV_KEYWORD_MAXLEN]) {
                unsigned u = t[SYV_KEYWORD_MAXLEN].as<unsigned>();
                return u;
            }
        } else break;
        if(/*a && */type.find_first_of(SYV_TYPE_ARRAY_OPEN) == 0) break;
        type = t[SYV_KEYWORD_TYPE].Scalar();
    } while(1!=2);

    return maxlen;
}

YAML::Node FormatValidator::getDefaultArray(YAML::Node def, std::string type, unsigned overriddenMaxlen, YAML::Node overrideDefault) {
    YAML::Node n, dflt;
    SYVDEBUGOUT(SYVTRACE, 
    printf("*** getDefaultArray, type='%s', dump(def):\n", type.c_str());
    dump(def);
    printf("dump(overrideDefault):\n");
    dump(overrideDefault);
    )

    unsigned maxlen = overriddenMaxlen;

    if(def) {
        type = def[SYV_KEYWORD_TYPE].Scalar();
        if(!maxlen) {
            maxlen = getEffectiveMaxlen(def);
        }
        dflt = overrideValues(def[SYV_KEYWORD_DEFAULT], overrideDefault);
    } else {
        if(!isType(type)) {
            throw ValidityException(syvTypeNotFound, "No %s!\n", SYV_KEYWORD_TYPE); //TODO: throw exception
            return n;
        }
        if(overrideDefault && !overrideDefault.IsNull()) dflt = overrideDefault;
    }
    std::string elementType = arrayElementType(type);
    bool elementTypeContainsArrayOpen = elementType.find(SYV_TYPE_ARRAY_OPEN) == 0;
    bool typeContainsArrayOpen = type.find(SYV_TYPE_ARRAY_OPEN) == 0;

    if(!isArrayType(type)) { return YAML::Node(YAML::NodeType::Undefined); }
    if(!typeContainsArrayOpen) {
        return getDefaultArray(getType(type), type, maxlen, dflt);
    }

    if(!maxlen) { // Don't generate infinite array
        if(dflt.IsDefined() && !dflt.IsNull()) {
            if(flags & syvArrayDefaultLengthIsMaxLen) {
                maxlen = dflt.size();
            } else {
                return dflt;
            }
        } else
            return YAML::Node(YAML::NodeType::Sequence);
    }

    YAML::Node t = getType(elementType);

    for(unsigned i = 0; i < maxlen; i++) {

        YAML::Node element;

        if(elementTypeContainsArrayOpen) {
            if(i < dflt.size()) {
                element = getDefaultArray(YAML::Node(YAML::NodeType::Undefined), elementType, 0, dflt[i]);
            } else {
                element = getDefaultArray(YAML::Node(YAML::NodeType::Undefined), elementType, 0);
            }
        } else {
            if(t && !t.IsNull()) {
                if(i < dflt.size())
                    element = getDefault(t, dflt[i]);
                else
                    element = getDefault(t);
            } else {
                element = YAML::Node(YAML::NodeType::Null);
            }
        }
        if(i < dflt.size()) { // TODO: there are 3 same if's in this loop. Move outside loop.
            n.push_back(element);
        } else {
            for(; i < maxlen; i++) {
                n.push_back(element);
            }
        }
    }

    return n;
}

YAML::Node FormatValidator::getDefaultStruct(YAML::Node def, YAML::Node dflt) {
    SYVDEBUGOUT(SYVTRACE, 
    printf("getDefaultStruct. dump(def):\n");
    dump(def);
    printf("dump(dflt):\n");
    dump(dflt);
    )

    YAML::Node r(YAML::NodeType::Undefined), strct(def[SYV_KEYWORD_STRUCT]);
    if(!strct) return r;
    for(YAML::Node::const_iterator i = strct.begin(); i != strct.end(); i++) {
        if(dflt[i->first.Scalar()])
            r[i->first.Scalar()] = getDefault(i->second, dflt[i->first.Scalar()]);
        else
            r[i->first.Scalar()] = getDefault(i->second);
    }
    return r;
}

YAML::Node FormatValidator::getDefaultEnum(YAML::Node def, YAML::Node overrideDefault) {
    SYVDEBUGOUT(SYVTRACE, 
    printf("getDefaultEnum(def, overrideDefault):\n");
    printf("def:\n");
    dump(def);
    printf("overrideDefault:\n");
    dump(overrideDefault);
    )

    if(overrideDefault && !overrideDefault.IsNull()) {
        YAML::Node enm = def[SYV_KEYWORD_ENUM];         // This needs to be written like this, workaround for problem with destructor of Node, which reset value in previous version.
        YAML::Node enumValues = enm[SYV_KEYWORD_VALUES];
        if(enumValues.IsMap()) {
            return enumValues[overrideDefault.Scalar()];
        } else {
            return overrideDefault;
        }
    } else if(YAML::Node enm = def[SYV_KEYWORD_ENUM]) {
        if(enm[SYV_KEYWORD_DEFAULT]) {
            YAML::Node enumValues = enm[SYV_KEYWORD_VALUES];
            if(enumValues.IsMap()) {
                std::string s = enm[SYV_KEYWORD_DEFAULT].Scalar();
                return copy(enumValues[s]);
            } else {
                return enm[SYV_KEYWORD_DEFAULT];
            }
        } else if(YAML::Node inh = enm[SYV_KEYWORD_INHERITS]) {
            YAML::Node first(YAML::NodeType::Undefined);
            for(YAML::Node::const_iterator i = inh.begin(); i != inh.end(); i++) {
                YAML::Node x = getDefaultEnum(getType(i->Scalar()), YAML::Node(YAML::NodeType::Undefined));
                if(x.IsDefined() && !x.IsNull()) {
                    if(first) {
                        return YAML::Node(YAML::NodeType::Undefined);
                    } else {
                        first = x;
                    }
                }
            }
            return first;
        } else {
            return YAML::Node(YAML::NodeType::Undefined);
        }
    } else {
        std::string type = def[SYV_KEYWORD_TYPE].Scalar();
        if(type.length()) {
            YAML::Node t = getType(type);
            return getDefaultEnum(t, overrideDefault);
        }
        return YAML::Node(YAML::NodeType::Undefined);
    }
}


YAML::Node FormatValidator::getDefault(YAML::Node def, YAML::Node overrideDefault, unsigned overrideMaxlen) {
    SYVDEBUGOUT(SYVTRACE,
    printf("getDefault: dump(def):\n");
    dump(def);
    printf("dump(overrideDefault):\n");
    dump(overrideDefault);
    )

    if(!valid || !def) return YAML::Node(YAML::NodeType::Undefined);

    YAML::Node dflt;
    std::string type = def[SYV_KEYWORD_TYPE].Scalar();

    if(!overrideMaxlen && def[SYV_KEYWORD_MAXLEN]) {
        overrideMaxlen = def[SYV_KEYWORD_MAXLEN].as<unsigned>();
    }

    if(def[SYV_KEYWORD_DEFAULT]) {
        dflt = overrideValues(def[SYV_KEYWORD_DEFAULT], overrideDefault);
    } else {
        dflt = overrideDefault;
    }

    SYVDEBUGOUT(SYVTRACE,
    printf("getDefault: dflt:\n");
    dump(dflt);
    )
    
    if(isBuiltinType(type))
        if(dflt)
            return dflt;
        else
            return YAML::Node(YAML::NodeType::Null);
    else if(type.find(SYV_TYPE_ARRAY_OPEN) == 0) {
        return getDefaultArray(def, "", overrideMaxlen, dflt);
    } else if(def[SYV_KEYWORD_STRUCT]) {
        return getDefaultStruct(def, dflt);
    } else if(def[SYV_KEYWORD_ENUM]) {
        return getDefaultEnum(def, dflt);
    } else {
        std::string tp = def[SYV_KEYWORD_TYPE].Scalar();
        YAML::Node n = getType(tp);
        if(!n) {
            return n;
        }
        std::string::size_type p;
        if((p = tp.find(SYV_STRUCT_MEMBER_SEPARATOR)) != std::string::npos) {
#if 0
            std::string structname;
            unsigned sz = strlen(SYV_STRUCT_MEMBER_SEPARATOR);
            do {
                structname += tp.substr(0, p);
                tp = tp.substr(p, tp.length() - p);
            } while((p = tp.find(SYV_STRUCT_MEMBER_SEPARATOR, sz)) != std::string::npos);
            std::string membername = tp.substr(sz, tp.length() - sz);
//            printf("qqq: structname='%s', membername='%s'\n", structname.c_str(), membername.c_str());
            YAML::Node structdefaults = getDefault(getType(structname));
//            printf("qqq: structdefaults van '%s':\n", structname.c_str());
//            dump(structdefaults);
            YAML::Node newdflt = overrideValues(structdefaults[membername], dflt);
            return getDefault(n, newdflt, overrideMaxlen);
#else
//            printf("qqq: %s\n", type.c_str());
            return getDefault(getType(type), dflt, overrideMaxlen);
#endif
        } else {
            return getDefault(n, dflt, overrideMaxlen);
        }
    }
}

std::string FormatValidator::getEffectiveFormat(YAML::Node def) {

    if(!def || def.IsNull()) return "";
    if(def[SYV_KEYWORD_ENUM]) return "";
    if(def[SYV_KEYWORD_STRUCT]) return "";
    
    std::string type = def[SYV_KEYWORD_TYPE].Scalar();
    YAML::Node format = def[SYV_KEYWORD_FORMAT];
    if(format) return format.Scalar();

    YAML::Node t = getType(type);
    if(!t || t.IsNull()) return "";

    return getEffectiveFormat(t);
}

bool FormatValidator::satisfiesTypeRequirements(std::string type, YAML::Node value, YAML::Node owningTypeDefinition) {
    SYVDEBUGOUT(SYVTRACE,
    printf("satisfiesTypeRequirements(%s, ...), dump(value):\n", type.c_str());
    dump(value);

    printf("satisfiesTypeRequirements, dump(value):\n");
    dump(value);

    printf("satisfiesTypeRequirements, dump(owningTypeDefinition):\n");
    dump(owningTypeDefinition);
    )

    if(value.IsScalar()) {
        std::string v = value.Scalar();
        std::string bt = getBaseType(type);
        if(isBuiltinType(bt)) {
            if(!bt.compare(SYV_TYPE_CHAR)) {
                if(v.length() > 1) {
                    throw ValidityException(syvInvalidValue, "Char expected, got \"%s\".\n", v.c_str());
                    return false;
                }
            } else if(isString(type)) { // TODO
                unsigned maxlen = getEffectiveMaxlen(owningTypeDefinition);
                if(maxlen && v.length() > maxlen) {
                    throw ValidityException(syvStringTooLong, "String \"%s\" exceeds %s of type \"%s\" (max %u).\n", v.c_str(), SYV_KEYWORD_MAXLEN, type.c_str(), maxlen);
                    return false;
                }
                std::string format = getEffectiveFormat(owningTypeDefinition);
                if(format.length()) {
                    if(!boost::regex_match(v, boost::regex(format))) {
                        throw ValidityException(syvFormatNotMatched, "Default value of \"%s\" doesn't match %s of \"%s\".\n", v.c_str(), SYV_KEYWORD_FORMAT, format.c_str());
//                        dump(owningTypeDefinition);
                        return false;
                    }
                }
            } else if(!bt.compare(SYV_TYPE_BOOL)) {
                if(!hasBooleanValue(value)) {
                    throw ValidityException(syvInvalidValue, "\"%s\" is not an accepted boolean value.\n", v.c_str());
                    return false;
                }
            } else if(isNumericType(bt)) {
                double min = getEffectiveMin(owningTypeDefinition);
                double max = getEffectiveMax(owningTypeDefinition);
                if(!isValidNumberForType(bt, value.Scalar())) return false;
                double d = value.as<double>();
                if(d < min) { throw ValidityException(syvValueUnderMin, "Value %f under %s of %f\n", d, SYV_KEYWORD_MIN, min); return false; }
                if(d > max) { throw ValidityException(syvValueOverMax, "Value %f over %s of %f\n", d, SYV_KEYWORD_MAX, max); return false; }
            } else return false;
        } else {
            YAML::Node t;// = owningTypeDefinition;
            if(!(t = getType(type)) && !isBuiltinType(type)) {
                throw ValidityException(syvTypeNotFound, "Could not find type \"%s\".\n", type.c_str()); return false; 
            }
            if(!t || t.IsNull()) return false; // ^^^^^^^^ TODO
            if(t[SYV_KEYWORD_TYPE]) {
                std::string st = t[SYV_KEYWORD_TYPE].Scalar();
                return satisfiesTypeRequirements(st, value, getType(st));
            } else if(t[SYV_KEYWORD_ENUM]) {
                return isValidValueForEnum(t, value);
            } else return false;
        }
    } else if(value.Type() == YAML::NodeType::Map) {
        if(!isTypeStruct(type)) {
            throw ValidityException(syvInvalidValue, "Map value passed to type '%s', which is not a %s.\n", type.c_str(), SYV_KEYWORD_STRUCT); return false; }
        std::string stype = type;
        YAML::Node structDefinition;
        do {
            YAML::Node tp = getType(stype);
            if(tp[SYV_KEYWORD_STRUCT]) { structDefinition = tp[SYV_KEYWORD_STRUCT]; break; }
            stype = tp[SYV_KEYWORD_TYPE].Scalar();
        } while(stype.length());
        if(!structDefinition) { printf("Error.\n"); return false; } // TODO
        for(YAML::Node::const_iterator i = value.begin(); i!=value.end(); i++) {
            YAML::Node k = i->first, v = i->second;
            if(!k.Scalar().compare(SYV_KEYWORD_INHERITS)) continue;
            if(!structDefinition[k.Scalar()]) {
                throw ValidityException(syvMemberNotFound, "Member \"%s\" not found in %s \"%s\"\n", k.Scalar().c_str(), SYV_KEYWORD_TYPE, type.c_str());
                return false;
            } else {
                YAML::Node n = structDefinition[k.Scalar()];
                if(n[SYV_KEYWORD_TYPE]) {
                    std::string membertype = n[SYV_KEYWORD_TYPE].Scalar();
                    if(isBuiltinType(membertype)) {
                        membertype = type + SYV_STRUCT_MEMBER_SEPARATOR + k.Scalar();
                    }
                    if(!satisfiesTypeRequirements(membertype, v, n)) return false;
                } else {
                    throw ValidityException(syvNoTypeSpecified, "No %s in %s\n", SYV_KEYWORD_TYPE, k.Scalar().c_str());
                    return false;
                }
            }
        }
    } else if(value.Type() == YAML::NodeType::Sequence) {
        std::string elementType = arrayElementType(type);
        YAML::Node std = getType(elementType);
        unsigned maxlen = getEffectiveMaxlen(std);
        if(maxlen && value.size() > maxlen) {
            throw ValidityException(syvArrayTooLong, "Array size(%lu) over %s of %u.\n", value.size(), SYV_KEYWORD_MAXLEN, maxlen);
            return false;
        }
        for(YAML::Node::iterator i = value.begin(); i != value.end(); i++) {
            if(!satisfiesTypeRequirements(elementType, *i, std)) return false;
        }
    } else if(value.IsNull()) {
        if(owningTypeDefinition) {
            bool b = getEffectiveAllowNull(owningTypeDefinition);
            if(!b) {
                throw ValidityException(syvInvalidValue, "Null as %s value, while %s evaluates to false.\n", SYV_KEYWORD_DEFAULT, SYV_KEYWORD_ALLOWNULL);
            }
            return b;
        }
        return false;
    } else if(!value.IsDefined()) {
        throw ValidityException(syvInvalidValue, "Got Undefined value.");
        return false;
    } else {
        throw ValidityException(syvInvalidNodeType, "Unknown node type(%u).\n", value.Type());
        return false;
    }

    return true;
}

std::string FormatValidator::getBaseType(std::string type) {
    if(isBuiltinType(type)) return type;
    if(isArrayType(type)) return type;
    YAML::Node t;
    t = getType(type);
    if(!t) {
        return type;
    }
    if(t[SYV_KEYWORD_ENUM] || t[SYV_KEYWORD_STRUCT] || !t[SYV_KEYWORD_TYPE]) return type; //TODO: !t[type] throw exception
    std::string tp = t[SYV_KEYWORD_TYPE].Scalar();
    return getBaseType(tp);
}

bool FormatValidator::verifyMin(YAML::Node def) {

    double min;

    if(def[SYV_KEYWORD_MIN]) {
        min = def[SYV_KEYWORD_MIN].as<double>();
    } else {
        min = -std::numeric_limits<double>::infinity();
    }

    std::string type = def[SYV_KEYWORD_TYPE].Scalar();

    do {
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            if(t[SYV_KEYWORD_MIN]) {
                double u = t[SYV_KEYWORD_MIN].as<double>();
                if(u > min) {
                    throw DDLException(syvValueUnderMin, "%s of %f is under previously defined %s of %f (in %s \"%s\").\n", SYV_KEYWORD_MIN, min, SYV_KEYWORD_MIN, u, SYV_KEYWORD_TYPE, type.c_str());
                    return false;
                } else return true;
            }
        } else break;
        type = t[SYV_KEYWORD_TYPE].Scalar();
    } while(1!=2);

    return true;
}

bool FormatValidator::verifyMax(YAML::Node def) {

    double max;

    if(def[SYV_KEYWORD_MAX]) {
        max = def[SYV_KEYWORD_MAX].as<double>();
    } else {
        max = std::numeric_limits<double>::infinity();
    }

    std::string type = def[SYV_KEYWORD_TYPE].Scalar();

    do {
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            if(t[SYV_KEYWORD_MAX]) {
                double u = t[SYV_KEYWORD_MAX].as<double>();
                if(u < max) {
                    throw DDLException(syvValueOverMax, "%s of %f is over previously defined %s of %f (in %s \"%s\").\n", SYV_KEYWORD_MAX, max, SYV_KEYWORD_MAX, u, SYV_KEYWORD_TYPE, type.c_str());
                    return false;
                } else return true;
            }
        } else break;
        type = t[SYV_KEYWORD_TYPE].Scalar();
    } while(1!=2);

    return true;
}

bool FormatValidator::verifyMaxlen(YAML::Node def) {

    unsigned maxlen;

    if(def[SYV_KEYWORD_MAXLEN]) {
        maxlen = def[SYV_KEYWORD_MAXLEN].as<unsigned>();
        if(maxlen == 0) {
            maxlen = std::numeric_limits<unsigned>::max();
        }
    } else {
        maxlen = 0; //std::numeric_limits<unsigned>::max();
    }

    std::string type = def[SYV_KEYWORD_TYPE].Scalar();

    do {
        bool a = isArrayType(type);
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            if(t[SYV_KEYWORD_MAXLEN]) {
                unsigned u = t[SYV_KEYWORD_MAXLEN].as<unsigned>();
                if(u == 0) {
                    u = std::numeric_limits<unsigned>::max();
                }
                if(u && (u < maxlen)) {
                    throw DDLException(syvStringTooLong, "%s of %d is over previously defined %s of %d (in %s \"%s\").\n", SYV_KEYWORD_MAXLEN, maxlen, SYV_KEYWORD_MAXLEN, u, SYV_KEYWORD_TYPE, type.c_str());
                    return false;
                } else {
                    break;
                }
            }
        } else break;
        if(a && type.find_first_of(SYV_TYPE_ARRAY_OPEN) == 0) {
            break;
        }
        type = t[SYV_KEYWORD_TYPE].Scalar();
    } while(1!=2);

    return true;
}


bool FormatValidator::ascertainDefaultLengthNotTooLarge(YAML::Node def, unsigned overrideMaxlen) {
    SYVDEBUGOUT(SYVTRACE,
    printf("ascertainDefaultLengthNotTooLarge(def, %u): dump(def):\n", overrideMaxlen);
    dump(def);
    )
    
    if(def[SYV_KEYWORD_STRUCT]) {
        YAML::Node strct = def[SYV_KEYWORD_STRUCT];
        for(YAML::Node::const_iterator i = strct.begin(); i!=strct.end(); i++) {
            unsigned maxlen = 0;
            if(!i->first.Scalar().compare(SYV_KEYWORD_INHERITS)) continue;
            if(i->second[SYV_KEYWORD_MAXLEN]) maxlen = i->second[SYV_KEYWORD_MAXLEN].as<unsigned>();
            if(!ascertainDefaultLengthNotTooLarge(i->second, maxlen)) return false;
        }
        return true;
    } else if(def[SYV_KEYWORD_ENUM]) {
        return true;
    } else {
        std::string type = def[SYV_KEYWORD_TYPE].Scalar();
        YAML::Node t = getType(type);
        if(t && !t.IsNull()) {
            unsigned maxlen = overrideMaxlen?overrideMaxlen:getEffectiveMaxlen(t);
            YAML::Node dflt = t[SYV_KEYWORD_DEFAULT];
            if(dflt && !def[SYV_KEYWORD_DEFAULT]) {
                unsigned dsize = 0;
                switch(dflt.Type()) {
                    case YAML::NodeType::Sequence:
                        dsize = dflt.size();
                        break;
                    case YAML::NodeType::Scalar:
                        dsize = dflt.Scalar().length();
                        break;
                    default:
                        return ascertainDefaultLengthNotTooLarge(t);
                }
                if(maxlen && dsize > maxlen) {
                    throw DDLException(syvInvalidValue, "Default value (defined in %s) does not fit. Provide new default or shorten effective default value.\n", type.c_str());
                    return false;
                }
            }
            return ascertainDefaultLengthNotTooLarge(t, maxlen);
        } else {
            return true;
        }
    }
}

bool FormatValidator::checkRefList(std::string type, std::vector<std::string>&types) {
    SYVDEBUGOUT(SYVTRACE,
    printf("[%s]\n", type.c_str());
    )

    std::string::size_type pos = type.find(SYV_TYPE_ARRAY_OPEN);

    unsigned sz = strlen(SYV_TYPE_ARRAY_OPEN);
    while(pos != std::string::npos) {
        std::string::size_type endpos = type.find_last_of(SYV_TYPE_ARRAY_CLOSE);
        if(endpos != std::string::npos) {
            type = type.substr(pos+sz, type.length() - sz - 1);
        } else {
            throw DDLException(syvInvalidArrayDeclaration, "No \"%c\" after \"%s\".\n", SYV_TYPE_ARRAY_CLOSE, SYV_TYPE_ARRAY_OPEN);
            return false;
        }
        pos = type.find(SYV_TYPE_ARRAY_OPEN);
    }

//    dump(types);

    if(std::find(types.begin(), types.end(), type) != types.end()) {
        throw DDLException(syvCyclicReferenceDetected, "Cyclic reference in \"%s\".\n", type.c_str());
        return false;
    }
    types.push_back(type);
#if SYV_MEMBER_REFERENCE_ILLEGAL
    if(type.find(SYV_STRUCT_MEMBER_SEPARATOR) != std::string::npos) {
        throw DDLException("\"%s\" illegal in type \"%s\" declaration.\n", SYV_STRUCT_MEMBER_SEPARATOR, type.c_str());
        return false;
    }
#else
    sz = strlen(SYV_STRUCT_MEMBER_SEPARATOR);
    if((pos = type.find(SYV_STRUCT_MEMBER_SEPARATOR)) != std::string::npos) {
        std::string structname = type.substr(0, pos);
//        types.push_back(structname);
//        if(std::find(types.begin(), types.end(), structname) != types.end()) {
//            dump(types);
//            throw DDLException("Cyclic reference in \"%s\".\n", structname.c_str());
//            return false;
//        }
//        if(!isTypeStruct(structname)) {
//            throw DDLException("No %s found with name \"%s\", or %s is not %s.\n", SYV_KEYWORD_STRUCT, structname.c_str(), SYV_KEYWORD_TYPE, SYV_KEYWORD_STRUCT);
//            return false;
//        }
        YAML::Node structdef;
        while(structname.length() && !isBuiltinType(structname) && !format[SYV_KEYWORD_TYPEDEFINITIONS][structname][SYV_KEYWORD_STRUCT]) {
            YAML::Node n = format[SYV_KEYWORD_TYPEDEFINITIONS][structname];
            structname = n[SYV_KEYWORD_TYPE].Scalar();
        }
        structdef = format[SYV_KEYWORD_TYPEDEFINITIONS][structname];
        std::string membername = type.substr(pos + sz, type.length() - pos - sz);
//        printf("%s'\n", membername.c_str());
        if((pos = membername.find(SYV_STRUCT_MEMBER_SEPARATOR)) != std::string::npos) {
            std::string member = membername.substr(0, pos);
            YAML::Node memberdef = structdef[SYV_KEYWORD_STRUCT][member];
            if(!memberdef) { // TODO: error message is off.
                throw DDLException(syvMemberNotFound, "No member '%s' found in %s '%s'.\n", member.c_str(), SYV_KEYWORD_TYPE, structname.c_str());
                return false;
            }
            std::string left = membername.substr(pos, membername.length() - pos);
            type = structdef[SYV_KEYWORD_STRUCT][member][SYV_KEYWORD_TYPE].Scalar() + left;
            return checkRefList(type, types);
        }
        YAML::Node memberdef = structdef[SYV_KEYWORD_STRUCT][membername];
        type = memberdef[SYV_KEYWORD_TYPE].Scalar();
        if(type.find(SYV_STRUCT_MEMBER_SEPARATOR) != std::string::npos) {
            return checkRefList(type, types);
        }
    }
#endif
    if(isBuiltinType(type)) {
        return true;
    }

    YAML::Node def = format[SYV_KEYWORD_TYPEDEFINITIONS][type];
    if(def) {
        if(def[SYV_KEYWORD_TYPE]) {
            type = def[SYV_KEYWORD_TYPE].Scalar();
            return checkRefList(type, types);
        } else if(def[SYV_KEYWORD_STRUCT]) {
            YAML::Node structdef = def[SYV_KEYWORD_STRUCT];
            for(YAML::Node::const_iterator i = structdef.begin(); i!=structdef.end(); i++) {
                if(!i->first.Scalar().compare(SYV_KEYWORD_INHERITS)) {
                    for(YAML::Node::const_iterator j = i->second.begin(); j != i->second.end(); j++) {
                        std::vector<std::string> copy = types;
                        if(!checkRefList(j->Scalar(), copy)) return false;
                    }
                    continue;
                }
                if(!i->second[SYV_KEYWORD_TYPE]) {
                    throw DDLException(syvNoTypeSpecified, "No %s in member %s, aborting.\n", SYV_KEYWORD_TYPE, i->first.Scalar().c_str());
                    return false;
                }
                std::vector<std::string> copy = types;
                if(!checkRefList(i->second[SYV_KEYWORD_TYPE].Scalar(), copy)) return false;
            }
            return true;
        }
    } else {
        throw DDLException(syvTypeNotFound, "%s definition of %s '%s' not found.\n", SYV_KEYWORD_TYPE, SYV_KEYWORD_TYPE, type.c_str());
//        return false;
    }

    return true;
}

bool FormatValidator::validateTypeDefinitionVarDefinition(YAML::Node n) {
    SYVDEBUGOUT(SYVTRACE,
    printf("validateTypeDefinitionVarDefinition(n)\n");
    printf("dump(n):\n");
    dump(n);)

    if(n.Type() != YAML::NodeType::Map) return false;
    if(!n[SYV_KEYWORD_TYPE] || !n[SYV_KEYWORD_TYPE].IsScalar()) return false;
    const char*keywords[] = {SYV_KEYWORD_TYPE, SYV_KEYWORD_MIN, SYV_KEYWORD_MAX, SYV_KEYWORD_MAXLEN, SYV_KEYWORD_FORMAT, SYV_KEYWORD_ALLOWNULL, SYV_KEYWORD_DEFAULT}; // TODO: not all, only applicable according to type.
    //TODO: add struct and enum here too. (anonymous struct and enum)
    const int numKeywords = 7;
    std::string stype = n[SYV_KEYWORD_TYPE].Scalar();

    if(!isType(stype)) {
        throw DDLException(syvTypeNotFound, "\"%s\" is not a %s.\n", stype.c_str(), SYV_KEYWORD_TYPE);
        return false;
    }

    unsigned maxlen = 0;

    for(int kw = 1; kw < numKeywords; kw++) {
        YAML::Node cur(n[keywords[kw]]);
        if(cur) {
            switch(kw) {
                case 1:   // min
                case 2: { // max
                    if(!cur.IsScalar()) return false;
                    if(!cur.IsScalar()) { throw DDLException(syvInvalidValue, "%s not scalar\n", kw==1?SYV_KEYWORD_MIN:SYV_KEYWORD_MAX); return false; }
                    std::string bt = getBaseType(stype);
                    if(!isValidNumberForType(bt, cur.Scalar())) { throw DDLException(syvInvalidValue, "\"%s\" invalid value for numeric %s \"%s\".\n", cur.Scalar().c_str(), SYV_KEYWORD_TYPE, bt.c_str()); return false; }
                    if(kw == 1 && !verifyMin(n)) { throw DDLException(syvInvalidValue, "%s not accepted.\n", SYV_KEYWORD_MIN); return false; }
                    else if(kw == 2 && !verifyMax(n)) { throw DDLException(syvInvalidValue, "%s not accepted.\n", SYV_KEYWORD_MAX); return false; }
                } break;
                case 3: { // maxlen
                    if(!cur.IsScalar()) { throw DDLException(syvInvalidValue, "%s not scalar\n", SYV_KEYWORD_MAXLEN); return false; }
                    if(!isString(stype) && !isArrayType(stype)) { throw DDLException(syvInvalidType, "Not %s or %s%c\n", SYV_TYPE_STRING, SYV_TYPE_ARRAY_OPEN, SYV_TYPE_ARRAY_CLOSE); return false; }
                    if(!isValidNumberForType(SYV_TYPE_UINT, cur.Scalar())) { throw DDLException(syvInvalidValue, "Invalid number\n"); return false; }
                    if(!verifyMaxlen(n)) { return false; }
                    maxlen = cur.as<unsigned>();
                } break;
                case 4: { // format
                    if(!cur.IsScalar()) { throw DDLException(syvInvalidValue, "%s not scalar\n", SYV_KEYWORD_FORMAT); return false; }
                    if(!isString(stype)) { throw DDLException(syvInvalidValue, "Format specified for %s that is not string.\n", SYV_KEYWORD_TYPE); return false; }
                } break;
                case 5: { // allowNull
                    if(!cur.IsScalar()) return false;
                    if(!hasBooleanValue(cur)) return false;
                } break;
                case 6: { // default
                    if(!satisfiesTypeRequirements(stype, cur, n)) { throw DDLException(syvInvalidValue, "%s value not accepted.\n", SYV_KEYWORD_DEFAULT); return false; }
                } break;
            }
        }
    }

    for(YAML::Node::const_iterator i = n.begin(); i != n.end(); i++) {
        const char**s = 0;
        for(s = keywords; s < keywords + numKeywords; s++) {
            if(!i->first.Scalar().compare(*s)) break;
        }
        if(s >= keywords + numKeywords) {
            throw DDLException(syvInvalidKeyword, "%s is not a keyword.\n", i->first.Scalar().c_str());
            return false;
        }
    }

    return ascertainDefaultLengthNotTooLarge(n, maxlen);
}

bool FormatValidator::validateTypeDefinitionStruct(YAML::Node n) {
    if(!n.Type() == YAML::NodeType::Map) { throw DDLException(syvMapExpected, "%s defined as %s but value is not a map.\n", SYV_KEYWORD_TYPE, SYV_KEYWORD_STRUCT); return false; }
    if(n.size() != 1) { throw DDLException(syvTooManyKeywords, "Parse error in %s.\n", SYV_KEYWORD_STRUCT); return false; }
    if(n[SYV_KEYWORD_STRUCT].size() < 1) { throw DDLException(syvEmptyStruct, "Empty %s is illegal.\n", SYV_KEYWORD_STRUCT); return false; }

#if 0
    YAML::Node structmembers = n[SYV_KEYWORD_STRUCT]; 
#else
    if(!StructMembers::isValid(this, n)) {
        return false;
    }
    YAML::Node structmembers = StructMembers::getStructMembers(this, n);//, structdef(YAML::NodeType::Map);
#endif

    for(YAML::Node::const_iterator i = structmembers.begin(); i != structmembers.end(); i++) {
        if(!i->first.Scalar().compare(SYV_KEYWORD_INHERITS)) continue;
        if(!validateTypeDefinitionVarDefinition(i->second)) return false;
    }

    return true;
}

bool FormatValidator::isTypeStruct(std::string type) {
    YAML::Node t = getType(type);
    if(!t) return false;
    else if(isTypeDefinitionStruct(t)) return true;
    else {
        std::string tp = t[SYV_KEYWORD_TYPE].Scalar();
        return isTypeStruct(tp);
    }
}

bool FormatValidator::isTypeDefinitionStruct(YAML::Node n) {
    if(!n.Type() == YAML::NodeType::Map) return false;
    if(!n[SYV_KEYWORD_STRUCT]) return false;
    if(n.size() != 1) return false;
    return true;
}

bool FormatValidator::isTypeDefinitionEnum(YAML::Node n) {
    if(!n.Type() == YAML::NodeType::Map) return false;
    if(!n[SYV_KEYWORD_ENUM]) return false;
    if(n.size() != 1) return false;
    return true;
}

bool FormatValidator::validateTypeDefinition(std::string name, YAML::Node n) {
    if(!n.Type() == YAML::NodeType::Map) return false;
    if(!name.length()) return false;

    
    try {
        std::vector<std::string> reflist;
        if(!checkRefList(name, reflist)) {
            throw DDLException(syvUnknownError, "Unknown error in type \"%s\".\n", name.c_str());
            return false;
        }

        if(isTypeDefinitionStruct(n)) {
            if(!validateTypeDefinitionStruct(n)) {
                throw DDLException(syvUnknownError, "Unknown error in %s %s \"%s\".", SYV_KEYWORD_STRUCT, SYV_KEYWORD_TYPE, name.c_str());
                return false;
            }
            YAML::Node structdef(YAML::NodeType::Map), structmembers = StructMembers::getStructMembers(this, n);
            structdef[SYV_KEYWORD_STRUCT] = structmembers;
            types[name] = structdef;
        } else if(isTypeDefinitionEnum(n)) {
            if(!validateTypeDefinitionEnum(name, n)) {
                throw DDLException(syvUnknownError, "Unknown error in %s %s \"%s\".", SYV_KEYWORD_ENUM, SYV_KEYWORD_TYPE, name.c_str());
                return false;
            }
#if 0
            YAML::Node enm(YAML::NodeType::Map), def(YAML::NodeType::Map), v = EnumValues::getEnumValues(this, n);
            def[SYV_KEYWORD_VALUES] = v;
            enm[SYV_KEYWORD_ENUM] = def;
            types[name] = enm;
#else
            types[name] = n;
#endif
        } else {
            if(!validateTypeDefinitionVarDefinition(n)) {
                throw DDLException(syvUnknownError, "Unknown error in %s \"%s\".\n", SYV_KEYWORD_TYPE, name.c_str());
                return false;
            }
            types[name] = n;
        }
    }
    catch(ValidityException e) {
        throw DDLException(e.error(), "In %s \"%s\":\n%s", SYV_KEYWORD_TYPE, name.c_str(), e.what());
    }

    return true;
}

bool FormatValidator::validateTypeDefinitions(YAML::Node n) {
    if(!n.Type() == YAML::NodeType::Map) return false;
    for(YAML::Node::const_iterator define = n.begin(); define != n.end(); define++) {
        YAML::Node k = define->first;

        if(types[k.Scalar()]) continue;

        YAML::Node v = define->second;
        try {
            if(!validateTypeDefinition(k.Scalar().c_str(), v)) {
                return false;
            }
        }
        catch(ValidityException e) {
            throw DDLException(e.error(), "%s definition '%s' has error(s):\n%s", SYV_KEYWORD_TYPE, k.Scalar().c_str(), e.what());
        }
    }
    return true;
}

bool FormatValidator::validateVariableLocations(YAML::Node n, std::string trace, int depth) throw(ValidityException) { //TODO: remove depth parameter
    if(n.IsMap()) {
        if(!n[SYV_KEYWORD_TYPE]) {
            for(YAML::Node::const_iterator i = n.begin(); i != n.end(); i++) {
                YAML::Node k = i->first;
                std::string element =  trace + SYV_VARIABLE_PATH_SEPARATOR + k.Scalar();
                YAML::Node v = i->second;
                if(!validateVariableLocations(v, element, depth + 1))
                    throw DDLException(syvUnknownError, "Variable location %s has an error.\n", element.c_str());
            }
        } else {
            if(!validateTypeDefinitionVarDefinition(n)) {
                throw DDLException(syvUnknownError, "Variable location %s has an error.\n", trace.c_str());
            }
        }
    } else if(n.IsSequence()) {
        return false;
    } else if(n.IsScalar()) {
        return false;
    }
    return true;
}

bool FormatValidator::validateFormat() {
    if(format.Type() != YAML::NodeType::Map) return false;
    YAML::Node td = format[SYV_KEYWORD_TYPEDEFINITIONS];
    try {
        if(!validateTypeDefinitions(td)) { return false; }
        for(YAML::Node::const_iterator i = format.begin(); i != format.end(); i++) {
            YAML::Node k = i->first;
            YAML::Node v = i->second;
            if(k.IsScalar()) {
                if(!k.Scalar().compare(SYV_KEYWORD_TYPEDEFINITIONS)) continue;
                if(!validateVariableLocations(v, k.Scalar())) {
                    throw DDLException(syvUnknownError, "Error in %s.\n", k.Scalar().c_str());
                    return false;
                }
            } else {
                throw DDLException(syvUnknownError, "That's weird, map key was not scalar!\n");
                return false;
            }
        }
    } catch(ValidityException& e) {
        throw DDLException(e.error(), e.what());
        return false;
    }
    return true;
}

bool FormatValidator::getEffectiveAllowNull(YAML::Node def, std::string type) { // TODO: this really is not quite as it should be yet. Rethink.
    SYVDEBUGOUT(SYVTRACE,
    printf("getEffectiveAllowNull(def, \"%s\")\n", type.c_str());
    dump(def);
    )

    if(!valid) return false; // TODO: throw exception

    if(!def || def.IsNull()) {
        std::string::size_type p;
        while((p = type.find(SYV_TYPE_ARRAY_OPEN)) != std::string::npos) {
            type = arrayElementType(type);
        }
        if(isBuiltinType(type)) return flags & syvAllowNullDefaultTrue;
        def = getType(type);
        if(!def) return false; // TODO: throw exception (should never be reached)
    }

    if(def[SYV_KEYWORD_ALLOWNULL]) {
        return def[SYV_KEYWORD_ALLOWNULL].as<bool>();
    }

    if(YAML::Node enm = def[SYV_KEYWORD_ENUM]) {
        if(enm[SYV_KEYWORD_ALLOWNULL])
            return enm[SYV_KEYWORD_ALLOWNULL].as<bool>();
        else
            return flags & syvAllowNullDefaultTrue; // TODO
    }

    if(YAML::Node strct = def[SYV_KEYWORD_STRUCT]) {
        for(YAML::Node::iterator i = strct.begin(); i != strct.end(); i++) {
            if(!i->first.Scalar().compare(SYV_KEYWORD_INHERITS)) continue;
            if(!getEffectiveAllowNull(i->second)) return false;
        }

        return true;
    }

    type = def[SYV_KEYWORD_TYPE].Scalar();
    YAML::Node t = getType(type);
    return getEffectiveAllowNull(t, type);
}
